using System;
using System.Collections.Generic;
using System.Text;
using Graphics;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using XMLConverter;

namespace Graphics3D
{
    public class XNASceneLoader
    {

        // map friendly names to array indices for our effects
        public enum EffectType
        {
            Default,
            Points,
            WireFrame,
            //Flat, // not supported on Xbox 360
            Gouraund,
            Rubber,
            Ceramic,
            Gold,
            Chrome,
            Copper,
            WorldsWorstToonShader,
            // ------
            Count
        };



        // initial effect for the teapot
        EffectType m_CurrentTeapotEffect = EffectType.Gold;

        // allocate storage for our collection of effects
        Effect[] m_effects = new Effect[(int)EffectType.Count];

        // our meshes (a teapot and some balls)
        XNAMesh m_meshTeapot = null;
        XNAMesh[] m_meshBall = new XNAMesh[(int)EffectType.Count];
        // make sure player doesn't change textures too fast
        private const double TEXTURE_DELAY = 0.25;
        private double m_timeSinceLastSelectNextEffect = TEXTURE_DELAY;

        public XNASceneLoader()
        {

        }

        public void Load(XNARenderer renderer, ref List<Object3D> scene, ref Camera camera)
        {

            string testPath = @"..\..\..\..\..\..\scenesXML\xnascene1.xml";
            // the environment map
            TextureCube m_texEnvironmentMap = renderer.Content.Load<TextureCube>(@"media\textures\c_olmForest_16M");

            XMLGeometryConverter converter = new XMLGeometryConverter();
            

            //----------------- CAMERA ----------------------
            camera = converter.ParseCamera(testPath);
            XNACamera xnaCamera = new XNACamera();
            xnaCamera.Location = new Vector3((float)camera.Position.X, (float)camera.Position.Y, (float)camera.Position.Z);
            camera = xnaCamera;

            //----------------- SCENE -----------------------
            List<Object3D> geometries = converter.ParseGeometries(testPath);
            foreach (Object3D geometry in geometries)
            {
                string meshPath = geometry.Mesh.Path;
                string shaderPath = geometry.BaseShader.Path;
                geometry.BaseShader = new XNAShader(renderer, shaderPath);
                geometry.Mesh = new XNAMesh(renderer, meshPath);

                //apply transformations
                float x = (float)geometry.Referential.T.X;
                float y = (float)geometry.Referential.T.Y;
                float z = (float)geometry.Referential.T.Z;
                geometry.Move(x,y,z);

                scene.Add(geometry);
            }

            //Object3D geometry = new Object3D();

            ////geometry.BaseShader = new XNAShader(renderer, @"media\effects\wireframe");
            //geometry.BaseShader = new XNAShader(renderer, @"media\effects\envmap");
            //(geometry.BaseShader as XNAShader).SetParameters("MaterialAmbientColor", Color.Black.ToVector4());
            //(geometry.BaseShader as XNAShader).SetParameters("MaterialEmissiveColor", Color.Black.ToVector4());
            //(geometry.BaseShader as XNAShader).SetParameters("MaterialSpecularPower", 8);
            //(geometry.BaseShader as XNAShader).SetParameters("EnvironmentMap", m_texEnvironmentMap);

            //geometry.Mesh = new XNAMesh(renderer, @"media\models\example");
            ////geometry.Mesh = new MyMesh(renderer, @"media\models\skybox2");
            ////geometry.Mesh = new MyMesh(renderer, @"media\models\tiger");
            ////geometry.Mesh = new MyMesh(renderer, @"media\models\lezard\lizardSIG.sdkmesh");
            //geometry.Rotate(0, 180, 0);



            //scene.Add(geometry);

            //Object3D geometry2 = new Object3D();

            ////geometry.BaseShader = new XNAShader(renderer, @"media\effects\wireframe");
            //geometry2.BaseShader = new XNAShader(renderer, @"media\effects\badtoon");
            //(geometry2.BaseShader as XNAShader).SetParameters("MaterialDiffuseColor", new Vector4(1.0f, 0.9f, 0.1f, 1.0f));
            //(geometry2.BaseShader as XNAShader).SetParameters("MaterialSpecularColor", new Vector4(0.9f, 0.9f, 0.9f, 1.0f));
            //(geometry2.BaseShader as XNAShader).SetParameters("MaterialSpecularPower", 2);
            //(geometry2.BaseShader as XNAShader).SetParameters("MaterialSpecularFalloff", 0.33f);

            //geometry2.Mesh = new XNAMesh(renderer, @"media\models\skybox2");
            ////geometry2.Mesh = new MyMesh(renderer, @"media\models\tiger");
            ////geometry2.Mesh = new MyMesh(renderer, @"media\models\lezard\lizardSIG.sdkmesh");
            //geometry2.Move(0, 0, 200);



            //scene.Add(geometry2);
        }

        #region test
        // set effect parameters for our the materials
        public void InitEffects(XNARenderer renderer,Model model)
        {
            // Default effect -- created by content pipeline when mesh 
            // is loaded without an attached effect
            BasicEffect basic =
                (BasicEffect)model.Meshes[0].MeshParts[0].Effect;
            basic.EnableDefaultLighting();
            basic.CurrentTechnique = basic.Techniques[0];
            m_effects[(int)EffectType.Default] =
                basic.Clone(renderer.Device.GraphicsDevice);

            // Points
            Effect points = renderer.Content.Load<Effect>(@"media\effects\point");
            points.Parameters["MaterialDiffuseColor"].
                SetValue(Color.White.ToVector4());
            m_effects[(int)EffectType.Points] =
                points.Clone(renderer.Device.GraphicsDevice);

            // WireFrame
            Effect wireframe =
                renderer.Content.Load<Effect>(@"media\effects\wireframe");
            wireframe.Parameters["MaterialDiffuseColor"].
                SetValue(Color.White.ToVector4());
            m_effects[(int)EffectType.WireFrame] =
                wireframe.Clone(renderer.Device.GraphicsDevice);

            //// Flat
            //Effect flat = 
            //    content.Load<Effect>(@"media\effects\flat");
            //flat.Parameters["MaterialDiffuseColor"].
            //    SetValue(new Vector4(1.0f, 0.9f, 0.1f, 1.0f));
            //flat.Parameters["MaterialSpecularColor"].
            //    SetValue(new Vector4(0.9f, 0.9f, 0.9f, 1.0f));
            //m_effects[(int)EffectType.Flat] = 
            //    flat.Clone(graphics.GraphicsDevice);

            // WorldsWorstToonShader
            Effect worldsWorstToonShader =
                renderer.Content.Load<Effect>(@"media\effects\badtoon");
            worldsWorstToonShader.Parameters["MaterialDiffuseColor"].
                SetValue(new Vector4(1.0f, 0.8f, 0.1f, 1.0f));
            worldsWorstToonShader.Parameters["MaterialSpecularColor"].
                SetValue(new Vector4(1.0f, 0.9f, 0.4f, 1.0f));
            worldsWorstToonShader.Parameters["MaterialSpecularPower"].
                SetValue(2);
            worldsWorstToonShader.Parameters["MaterialSpecularFalloff"].
                SetValue(0.33f);
            m_effects[(int)EffectType.WorldsWorstToonShader] =
                worldsWorstToonShader.Clone(renderer.Device.GraphicsDevice);

            // load environment map effect and set common properties once
            Effect effect = renderer.Content.Load<Effect>(@"media\effects\envmap");
            effect.Parameters["MaterialAmbientColor"].
                SetValue(Color.Black.ToVector4());
            effect.Parameters["MaterialEmissiveColor"].
                SetValue(Color.Black.ToVector4());
            effect.Parameters["MaterialSpecularPower"].
                SetValue(8);
            //effect.Parameters["EnvironmentMap"].
            //    SetValue(m_texEnvironmentMap);
            //effect.CurrentTechnique = effect.Techniques[0];

            // Gouraund
            effect.Parameters["MaterialDiffuseColor"].
                SetValue(new Vector4(1.0f, 0.9f, 0.1f, 1.0f));
            effect.Parameters["MaterialSpecularColor"].
                SetValue(new Vector4(0.9f, 0.9f, 0.9f, 1.0f));
            effect.Parameters["EnvironmentWeight"].
                SetValue(0.00f);
            m_effects[(int)EffectType.Gouraund] =
                effect.Clone(renderer.Device.GraphicsDevice);

            // RedRubber
            effect.Parameters["MaterialDiffuseColor"].
                SetValue(new Vector4(1.0f, 0.1f, 0.1f, 1.0f));
            effect.Parameters["MaterialSpecularColor"].
                SetValue(new Vector4(0.9f, 0.7f, 0.7f, 1.0f));
            effect.Parameters["EnvironmentWeight"].
                SetValue(0.00f);
            m_effects[(int)EffectType.Rubber] =
                effect.Clone(renderer.Device.GraphicsDevice);

            // RedCeramic
            effect.Parameters["MaterialDiffuseColor"].
                SetValue(new Vector4(1.0f, 0.1f, 0.1f, 1.0f));
            effect.Parameters["MaterialSpecularColor"].
                SetValue(new Vector4(0.9f, 0.9f, 0.9f, 1.0f));
            effect.Parameters["EnvironmentWeight"].
                SetValue(0.125f);
            m_effects[(int)EffectType.Ceramic] =
                effect.Clone(renderer.Device.GraphicsDevice);

            // Gold
            effect.Parameters["MaterialDiffuseColor"].
                SetValue(new Vector4(1.0f, 0.9f, 0.1f, 1.0f));
            effect.Parameters["MaterialSpecularColor"].
                SetValue(new Vector4(0.9f, 0.9f, 0.9f, 1.0f));
            effect.Parameters["EnvironmentWeight"].
                SetValue(0.50f);
            m_effects[(int)EffectType.Gold] =
                effect.Clone(renderer.Device.GraphicsDevice);

            // Chrome
            effect.Parameters["MaterialDiffuseColor"].
                SetValue(new Vector4(0.8f, 0.8f, 0.8f, 1.0f));
            effect.Parameters["MaterialSpecularColor"].
                SetValue(new Vector4(0.9f, 0.9f, 0.9f, 1.0f));
            effect.Parameters["EnvironmentWeight"].
                SetValue(0.80f);
            m_effects[(int)EffectType.Chrome] =
                effect.Clone(renderer.Device.GraphicsDevice);

            // Copper
            effect.Parameters["MaterialDiffuseColor"].
                SetValue(new Vector4(1.0f, 0.1f, 0.1f, 1.0f));
            effect.Parameters["MaterialSpecularColor"].
                SetValue(new Vector4(0.9f, 0.9f, 0.9f, 1.0f));
            effect.Parameters["EnvironmentWeight"].
                SetValue(0.70f);
            m_effects[(int)EffectType.Copper] =
                effect.Clone(renderer.Device.GraphicsDevice);
        }

        // init meshes before first use
        public void InitMyMeshes(Model model)
        {
            // init teapot
            if (m_meshTeapot == null)
            {
                m_meshTeapot = new XNAMesh();
                //m_meshTeapot.Rotate(0, 180, 0);
            }
            //m_meshTeapot.Model = model;
            m_meshTeapot.MeshName = "Teapot01";
            SelectEffect(m_CurrentTeapotEffect);

            // init balls (one mesh, multiple instances)
            float angle = 360.0f / (float)(m_meshBall.Length);
            for (int i = 0; i < m_meshBall.Length; i++)
            {
                if (m_meshBall[i] == null)
                {
                    m_meshBall[i] = new XNAMesh();
                    //m_meshBall[i].RotateTo(0, i * angle, 0);
                }
                //m_meshBall[i].Model = model;
                m_meshBall[i].MeshName = "Sphere01";
                //m_meshBall[i].Effect = m_effects[i];
            }
        }

        // map our enums to actual effects, apply selected effect to teapot
        public void SelectEffect(EffectType type)
        {
            m_CurrentTeapotEffect = type;
            //m_meshTeapot.Effect = m_effects[(int)type];
        }

        // cycle to next effect
        public void SelectNextEffect()
        {
            // if delay has elapsed
            if (m_timeSinceLastSelectNextEffect >= TEXTURE_DELAY)
            {
                // cycle through all available effects
                if (m_CurrentTeapotEffect == EffectType.Count - 1)
                {
                    SelectEffect(EffectType.Default);
                }
                else
                {
                    SelectEffect(m_CurrentTeapotEffect + 1);
                }

                // reset dealy timer
                m_timeSinceLastSelectNextEffect = 0;
            }
        }
        #endregion

    }
}
